<?php
namespace library;
use library\Inspector as Inspector;
/**
 *klasa bazowa dla innych klas
 *
 * @author Damian Jóźwiak
 */
abstract class Base {
    /**
     *
     * @var Inspector
     */
    protected $inspector;
  //  private  $options;
    public function __construct($options = array()) {
      //  $this->options=$options;
        $this->inspector = new Inspector($this);
        if (is_array($options) || is_object($options)){
            foreach ($options as $key=>$value){
                
                $key = ucfirst($key);
                $method ="set{$key}";
                $this->$method($value);
            }
        }
    }
    protected function _getExceptionForProperty($property){
        return new \library\exceptions\ExceptionProperty("własność {$property} nie istnieje");
        
    }

    protected function _getExceptionForReadOnly($property){
        return new \library\exceptions\ExceptionReadOnly("{$property} jest tylko do odczytu");
    }
    protected function _getExceptionForWriteOnly($property){
        return new \library\exceptions\ExceptionWriteOnly("{$property} jest tylko do zapisu");
    }
    protected function _getExceptionForImplementation($method){
        return new \library\exceptions\ExceptionMethodNotImplemented("Metoda {$method} nie jest zaimplementowana");
    }

    public function __call($name, $arguments) {
        if (empty($this->inspector)){
            throw  new \Exception("wywołaj metodą parent::__construct");
        }
        $getMatches = StringMethods::match($name,"^get([a-zA-Z0-9]+)$");
        if (sizeof($getMatches)>0){
            $normalized = lcfirst($getMatches[0]);
            $property = "{$normalized}";            
            if (property_exists($this, $property)){
                $meta = $this->inspector->getPropertyMeta($property);
                if (empty($meta["@readwrite"]) && empty($meta["@read"])){
                    throw $this->_getExceptionForWriteOnly($normalized);
                }
                if (isset($this->$property)){
                    return $this->$property;
                }
                return null;
            }
            else if (property_exists($this, ucfirst($property))){
                $meta = $this->inspector->getPropertyMeta(ucfirst($property));
                if (empty($meta["@readwrite"]) && empty($meta["@read"])){
                    throw $this->_getExceptionForWriteOnly($normalized);
                }
                if (isset($this->$property)){
                    return $this->$property;
                }
                return null;
            }
            else   {
                throw $this->_getExceptionForProperty ($property);
            }
        }
        $setMatches = StringMethods::match($name, "^set([a-zA-Z0-9]+)$");
        if (sizeof($setMatches)>0){            
            $normalized = lcfirst($setMatches[0]);
            $property = "{$normalized}";            
            if (property_exists($this, $property)){
             $meta = $this->inspector->getPropertyMeta($property);
                 if (empty($meta["@readwrite"]) && empty($meta["@write"])){
                    throw $this->_getExceptionForReadOnly($normalized);
                }
                $this->$property = $arguments[0];
                return $this;
            }
            else if (property_exists($this, ucfirst($property))) {
                $meta = $this->inspector->getPropertyMeta($property);
                if (empty($meta["@readwrite"]) && empty($meta["@write"])) {
                    throw $this->_getExceptionForReadOnly($normalized);
                }
                $prop = ucfirst($property);
                $this->$prop = $arguments[0];
                return $this;
            }
        }
        throw $this->_getExceptionForImplementation($name);                
    }
    public function __get($name) {
        $function = "get".  ucfirst($name);
        return $this->$function();
    }
    public function __set($name,$value) {
        $function = "set".  ucfirst($name);
        return $this->$function($value);
    }
}
